package com.dobbinsoft.iotechn.device.mqtt.handler;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.dobbinsoft.iotechn.data.compent.CacheComponent;
import com.dobbinsoft.iotechn.device.constant.DeviceConst;
import com.dobbinsoft.iotechn.device.domain.DeviceDataDO;
import com.dobbinsoft.iotechn.device.domain.ProductDataDO;
import com.dobbinsoft.iotechn.device.entity.DeviceSessionDataEntity;
import com.dobbinsoft.iotechn.device.entity.DeviceSessionEntity;
import com.dobbinsoft.iotechn.device.enums.IotMessageResultType;
import com.dobbinsoft.iotechn.device.enums.IotMessageType;
import com.dobbinsoft.iotechn.device.mapper.DeviceDataMapper;
import com.dobbinsoft.iotechn.device.mq.message.DeviceDataInnerMessage;
import com.dobbinsoft.iotechn.device.mqtt.message.IotDeviceDataMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;

/**
 * Description:
 * User: rize
 * Date: 2020/6/26
 * Time: 14:30
 */
public class IotMqttDataMessageHandler implements IotMqttMessageHandler<IotDeviceDataMessage> {

    private static final Logger logger = LoggerFactory.getLogger(IotMqttDataMessageHandler.class);

    @Autowired
    private CacheComponent cacheComponent;

    @Autowired
    private DeviceDataMapper deviceDataMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public int handle(String accessKeyId, IotDeviceDataMessage msg) {
        // 从设备Hash表中读取设备，上线设备必定存在于此Hash表中
        DeviceSessionEntity deviceSessionEntity = cacheComponent.getHashObj(DeviceConst.CA_DEVICE_HASH, accessKeyId, DeviceSessionEntity.class);
        if (deviceSessionEntity == null) {
            return IotMessageResultType.ERROR_FATAL.getCode();
        }
        // 处理设备数据点
        DeviceSessionDataEntity dataEntity = cacheComponent
                .getHashObj(DeviceConst.CA_DEVICE_DATA_HASH + deviceSessionEntity.getId(),
                        msg.getDataPoint(),
                        DeviceSessionDataEntity.class);
        long lastUpdate = 0;
        long lastPersist = 0;
        if (dataEntity != null) {
            lastUpdate = dataEntity.getLastUpdate();
            lastPersist = dataEntity.getLastPersist();
        }
        ProductDataDO productData = deviceSessionEntity.getProductDataMap().get(msg.getDataPoint());
        if (productData == null) {
            return IotMessageResultType.ERROR_FATAL.getCode();
        }
        long current = System.currentTimeMillis();
        if (current - lastUpdate < 1000 * productData.getRefreshPeriod()) {
            // 若小于频率
            Integer credit = deviceSessionEntity.getCredit();
            if (credit <= 0) {
                // 若信用为0，则直接将其踢下线
                return IotMessageResultType.ERROR_FATAL.getCode();
            }
            // 更新
            deviceSessionEntity.setCredit(deviceSessionEntity.getCredit() - 1);
            cacheComponent.putHashObj(DeviceConst.CA_DEVICE_HASH, accessKeyId, deviceSessionEntity);
            logger.warn("[设备高频访问] " + accessKeyId);
        }
        // 判断该次数据是否需要持久化
        if (current - lastPersist > 1000 * productData.getPeriod()) {
            // 进行持久化
            lastPersist = current;
            DeviceDataDO updateDeviceData = new DeviceDataDO();
            updateDeviceData.setValue(msg.getData());
            deviceDataMapper.update(updateDeviceData,
                    new QueryWrapper<DeviceDataDO>()
                            .eq("device_id", deviceSessionEntity.getId())
                            .eq("id_tag", msg.getDataPoint()));
        }
        // 将数据点更新到数据Hash表中
        // 是否要检验数据类型？
        DeviceSessionDataEntity newSessionData = new DeviceSessionDataEntity();
        newSessionData.setType(productData.getType());
        newSessionData.setLastUpdate(current);
        newSessionData.setLastPersist(lastPersist);
        newSessionData.setValue(msg.getData());
        cacheComponent.putHashObj(DeviceConst.CA_DEVICE_DATA_HASH + deviceSessionEntity.getId(), msg.getDataPoint(), newSessionData);

        // 将数据变化 通知用户网关
        DeviceDataInnerMessage message = new DeviceDataInnerMessage();
        message.setDeviceId(deviceSessionEntity.getId());
        message.setUserId(deviceSessionEntity.getUserId());
        message.setAccessKeyId(accessKeyId);
        message.setIdTag(msg.getDataPoint());
        message.setValue(msg.getData());
        message.setType(productData.getType());
        stringRedisTemplate.convertAndSend("API_GW", JSONObject.toJSONString(message));
        return IotMessageResultType.SUCCESS.getCode();
    }

    @Override
    public int getCode() {
        return IotMessageType.DATA_POINT.getCode();
    }

    @Override
    public Class<IotDeviceDataMessage> getMessageType() {
        return IotDeviceDataMessage.class;
    }

}
